home *** CD-ROM | disk | FTP | other *** search
/ PsL Monthly 1993 December / PSL Monthly Shareware CD-ROM (December 1993).iso / prgmming / dos / c / chkseg.com / CHKSEG.C < prev    next >
Encoding:
C/C++ Source or Header  |  1988-11-16  |  57.0 KB  |  1,557 lines

  1. /*
  2.  
  3.          +--------------------------------------------------+
  4.          !                                                  !
  5.          !     Segment Call Checking Program                !
  6.          !                                                  !
  7.          +--------------------------------------------------+
  8.  
  9. */
  10.  
  11. /*
  12.          +--------------------------------------------------+
  13.          !                                                  !
  14.          !              Include Files                       !
  15.          !                                                  !
  16.          +--------------------------------------------------+
  17. */
  18.                     
  19. #include <stdio.h>
  20. #include <stdlib.h>
  21. #include <fcntl.h>
  22. #include <ctype.h>
  23. #include <dos.h>
  24. #include "symdefs.h"       
  25.  
  26. /*
  27.          +--------------------------------------------------+
  28.          !                                                  !
  29.          !              Define Declarations                 !
  30.          !                                                  !
  31.          +--------------------------------------------------+
  32. */
  33.  
  34. #define   MAXFILES     600                 /*  Max. No. of Files Allowed    */
  35. #define   MAXPATH       67                 /*  Max. Path length             */
  36. #define   MAXREFS      800                 /*  Max. Proc. Refs. / Proc.     */
  37. #define   MAXSEGS       20                 /*  Max. number of segments      */
  38. #define   MAXOVLF      300                 /*  Max. files for all segments  */
  39.                                            /*   in load statement           */
  40. typedef     struct    linenode  {
  41.    char    *procedure                   ;  /*  Procedure name called        */
  42.    struct   linenode *nextlinenode      ;  /*  Pointer to next procedure    */
  43. }  LINENODE , *LINENODEPTR ;
  44.  
  45. typedef     struct    wordnode  {
  46.    char              *word              ;   /*  Procedure name              */
  47.    char              *filename          ;   /*  File name where defined     */
  48.    int                linenumber        ;   /*  Line number where defined   */
  49.    int                printpage         ;   /*  Page where printed          */
  50.    LINENODEPTR        firstlinenode     ;   /*  First procedure called      */
  51.    LINENODEPTR        lastlinenode      ;   /*  Last procedure called       */
  52.    struct   wordnode *left              ;   /*  Pointer to last word node   */
  53.    struct   wordnode *right             ;   /*  Pointer to next word node   */
  54. }  WORDNODE, *WORDNODEPTR ;
  55.  
  56. typedef    struct     filesegs  {               
  57.    char              *filename          ;   /*  filename                    */
  58.    int                filesegno         ;   /*  Segment number of filename  */
  59.    struct  filesegs  *nextfileseg       ;   /*  Pointer to next file seg.   */
  60. }  FILESEG, *FILESEGPTR ;
  61.  
  62. typedef     struct key_entry  {
  63.    int      length   ;                      /*  Length of key               */
  64.    char    *key      ;                      /*  Pointer to key              */
  65. }  KEYWORD , *KEYWORDPTR ;
  66.  
  67. /*
  68.          +--------------------------------------------------+
  69.          |                                                  |
  70.          |              Global Declarations                 |
  71.          |                                                  |
  72.          +--------------------------------------------------+
  73. */
  74.  
  75. int       NoOfFileSegs             =  0   ; /*  Number of file segments     */
  76. FILESEG   FileSegs  [MAXOVLF]      = {0}  ; /*  List of files with segments */
  77. LINENODE  Segments  [MAXSEGS]      = {0}  ; /*  List of procs. in segments  */
  78. int       CurrentSegment           =  0   ; /*  Current Segment             */
  79.  
  80. FILE     *InputFile                = NULL ;
  81. char      InputFileName[MAXPATH]   = {""} ;
  82. unsigned  InputLineNumber          = 0    ;
  83. char      InputLine [4*MAX_INPUT]  = {""} ;
  84. long      TotalLines               = 0L   ;
  85. int       eofflag                  = FALSE;
  86. int       totalsymbols             = 0    ;
  87. NSCB      nscb = { 0, 0, 0 }              ; /*  Symbol Control Block        */
  88.  
  89. FILE     *OutputFile               = NULL ;
  90. int       OutputLineNumber         = 60   ;
  91. int       OutputPage               = 0    ;
  92. char      OutputFileName [MAXPATH] = {""} ;
  93.  
  94. long      xtime                    = 0L   ;
  95. char      datetime [28]            = {""} ;
  96.  
  97. int       nestlevel                =  0   ; /* Indicates { nesting level    */
  98. int       maxlevel                 =  0   ; /* Maximum level to process     */
  99. int       nrfiles                  =  0   ; /* Number of files processed    */
  100. int       librarycalls             = FALSE; /* Process library procs?       */
  101. int       linereferences           = FALSE; /* List proc line numbers?      */
  102. int       poundsign                = FALSE; /* TRUE if # directive on input */
  103. char      filetemplate [MAXPATH]   = {""} ;
  104. char      fulltemplate [MAXPATH]   = {""} ;
  105. char      pathname     [MAXPATH]   = {""} ;
  106. char     *filenames [MAXFILES]     ={NULL}; /* Pointers to file names       */
  107. char     *procedure                = NULL ; /* Pointer to current procedure */
  108. char     *calledprocedure          = NULL ;
  109. char      number    [11]           = {0}  ;
  110. struct    find_t  filespec         = {""} ;
  111. char      margin [] = { "       " }       ; /* Left margin for print out    */
  112.  
  113. int       Compare ()                      ;
  114. extern    FILE      *fopen   ()           ;
  115. extern    void      *malloc  ()           ;
  116.  
  117. main ( )
  118.  
  119. /*
  120.    +-------------------------------------------------------+
  121.    |                                                       |
  122.    |  This program may be used to check the segmentation   |
  123.    |  structure of a program for calls which invoke a      |
  124.    |  segment not in the calling heirarchy.  It reads      |
  125.    |  the MSC link segment directives, performs a cross-   |
  126.    |  reference on all 'C' files which are invoked in      |
  127.    |  the load, and then checks each procedure within      |
  128.    |  each segment to insure the procedures which are      |
  129.    |  called (up to a user specifiable maximum depth)      |
  130.    |  are either in the segment being checked or are in    |
  131.    |  the root.  A trace back of calling sequences which   |
  132.    |  don't meet these conditions is written to a file     |
  133.    |  for inspection.                                      |
  134.    |                                                       |
  135.    |  This program should be compiled using the large      |
  136.    |  data model (compact, large, huge) and linked         |
  137.    |  with a stack size of about 32000 bytes.  The large   |
  138.    |  stack size is required because of the recursive      |
  139.    |  procedures used.                                     |
  140.    |                                                       |
  141.    |                                                       |
  142.    |  Author: Willard Gersbacher  CompuServID [76117,2611] |
  143.    |                                                       |
  144.    +-------------------------------------------------------+
  145. */
  146.  
  147. {
  148.    char         value [MAX_SYMBOL] ;
  149.    char        *ctime  ()          ;
  150.    WORDNODEPTR  tree               ;
  151.    WORDNODEPTR  AddToTree ()       ;
  152.    LINENODEPTR  lptr               ;
  153.    int          done               ;
  154.    int          Processing         ;
  155.    int          i, max             ;
  156.   
  157.  
  158.    printf ( "\nCheck Segments (CHKSEG)      V1.0\n\n" ) ;
  159.  
  160.    for ( done = 0 ; done < MAXSEGS ; done++ ) {
  161.       Segments [done].procedure    = NULL  ;
  162.       Segments [done].nextlinenode = NULL  ;
  163.    } ;
  164.  
  165.    if ( ! GetFileSegments () )              /* Get File Segments   */
  166.       exit (0) ;
  167.  
  168.    GetTraceFile () ;                        /* Get Trace File name */
  169.  
  170.    Initialize ( TRUE ) ;                    /* Initialize program  */
  171.  
  172.    time ( &xtime ) ;
  173.    strncpy ( datetime, ctime ( &xtime ), 24 ) ;
  174.    datetime [24] = '\0' ;
  175.  
  176.    Processing = TRUE ;
  177.    tree       = NULL ;
  178.  
  179.    while ( Processing ) {                   /* Main processing loop */
  180.       do {
  181.          nscb.nextt = nscb.nextp = nscb.nextc = 0 ;
  182.          if ( eofflag != EOF ) {
  183.             while ( GetNextProc ( value )  ) {
  184.                if ( nestlevel == 0 ) {
  185.                   if ((procedure = (char *)malloc(strlen(value)+1)) == NULL) {
  186.                      printf ( "Out of memory\n" ) ;
  187.                      exit ( 1 ) ;
  188.                   } ;
  189.                   strcpy ( procedure, value ) ;
  190.                   tree = AddToTree ( tree, value, InputLineNumber ) ;
  191.                }
  192.                else {
  193.                   tree = AddToTree ( tree, value, -1 ) ;
  194.                   addtree ( tree, procedure, value ) ;
  195.                } ;
  196.             } ;
  197.             TotalLines += InputLineNumber ;
  198.          } ;
  199.       }  while ( OpenNextFile () ) ;
  200.       printf ( "Cross-reference complete!!                               " ) ;
  201.  
  202.       printf ("\n\nTotal number of procedures processed . %7d\n",totalsymbols);
  203.       printf (    "Total number of lines processed  . . . %7ld\n",TotalLines);
  204.  
  205.       do {
  206.          printf ( "\nInclude another template?\n" ) ;
  207.          printf ( ">>> " ) ;
  208.          if ( FGetLine ( stdin, value, MAX_SYMBOL ) > 0 && 
  209.               toupper  (value [0]) == 'Y'                    ) {
  210.             nrfiles++     ;
  211.             Initialize ( FALSE ) ;
  212.          }
  213.          else if ( toupper (value[0]) == 'N' )
  214.             Processing = FALSE   ;
  215.       }  while ( toupper (value[0]) != 'Y' && toupper (value[0]) != 'N' ) ;
  216.    } ;
  217.  
  218.    done = FALSE ;
  219.    while ( ! done ) {
  220.       printf ( "Maximum call depth to trace?\n" ) ;
  221.       printf ( ">>> " ) ;
  222.       FGetLine ( stdin, number, 10 ) ;
  223.       maxlevel = atoi ( number) ;
  224.       if ( maxlevel > 0 )
  225.          done = TRUE ;
  226.    } ;
  227.  
  228.       /*  Trace down all segments looking for procedures which are
  229.           not either in the same segment as we are currently looking at
  230.           or in the root.   */
  231.  
  232.    done = 0 ;
  233.    while ( Segments [++done].procedure != NULL ) {
  234.       printf  ( "\nChecking segment number %d\n", done ) ;
  235.       sprintf ( InputLine, "  Segment Check for segment number %d", done ) ;
  236.       printline ( ""        ) ;
  237.       printline ( InputLine ) ;
  238.       lptr = &Segments [done] ;
  239.       CurrentSegment = done   ;
  240.       while ( lptr != (LINENODEPTR) NULL ) {
  241.          nestlevel = 0  ;
  242.          printf ( "...Working on %s", lptr->procedure ) ;
  243.          max = 32 - strlen ( lptr->procedure ) ;
  244.          for ( i = 0 ; i < max ; i++ )
  245.             putchar ( ' ' ) ;
  246.          putchar ( '\r' ) ;
  247.          checktree ( tree, tree, lptr->procedure  ) ;
  248.          lptr = lptr->nextlinenode ;
  249.       }  ;
  250.       printf ( "              " ) ;
  251.       for ( i = 0 ; i < 32 ; i++ )
  252.          putchar ( ' ' ) ;
  253.       putchar ( '\r' ) ;
  254.    } ;
  255.    
  256.    putc    ( '\x1a', OutputFile  ) ;       /* Write EOF byte */
  257.    fclose ( OutputFile ) ;
  258. }
  259.  
  260. Initialize ( first ) 
  261.  
  262.    int   first    ;            /* TRUE if this is first call  */
  263.  
  264. /*
  265.          +--------------------------------------------------+
  266.          !                                                  !
  267.          !         Initialize the CHKSEG  Program           !
  268.          !                                                  !
  269.          +--------------------------------------------------+
  270. */
  271.  
  272. {
  273.    int   length    , FileName , i, max ;
  274.  
  275.    FileName = FALSE ;
  276.    while ( ! FileName ) {
  277.       printf ( "\nEnter template for file cross-reference.\n" ) ;
  278.       printf ( ">>> " ) ;
  279.       length = FGetLine ( stdin, InputLine, 40 ) ;
  280.       if ( length > 0 ) 
  281.          strcpy ( filetemplate, InputLine ) ;
  282.       else
  283.          continue ;
  284.       ExpandTemplate ( filetemplate, fulltemplate, pathname ) ;
  285.    
  286.       /*  Get the files associated with template  */
  287.  
  288.       length = _dos_findfirst ( filetemplate, _A_NORMAL , &filespec ) ;
  289.       if ( length != 0 ) 
  290.          printf ( "Not able to retrieve anything with that template\n");
  291.       else 
  292.          FileName = TRUE ;
  293.    } ;
  294.  
  295.    InputLineNumber = 0 ;
  296.    filenames [nrfiles] = malloc ( strlen ( filespec.name ) + 1 ) ;
  297.    if ( filenames [nrfiles] == NULL ) {
  298.       printf ( "Out of memory\n" ) ;
  299.       exit ( 1 ) ;
  300.    } ;
  301.    strcpy ( filenames [nrfiles] , filespec.name ) ;
  302.    strcpy ( InputFileName, pathname ) ;
  303.    strcat ( InputFileName, filespec.name ) ;
  304.    if ( ( InputFile = fopen ( InputFileName, "r" ) ) == NULL ) {
  305.       printf ( "Unable to open file -> %s\n", InputFileName ) ;
  306.       eofflag = EOF ;
  307.    }
  308.    else {
  309.       SetSegmentNumber ( filenames [nrfiles] ) ;
  310.       eofflag = FGetLine ( InputFile, InputLine, 2*MAX_INPUT ) ;
  311.       if ( eofflag == EOF )
  312.          printf ( "Empty input file -> %s\n", InputFileName ) ;
  313.       else {
  314.          printf ( "Cross-referencing file %s", InputFileName ) ;
  315.          max = 32 - strlen ( InputFileName ) ;
  316.          for ( i = 0 ; i < max ; i++ )
  317.             putchar ( ' ' ) ;
  318.          putchar ( '\r' ) ;
  319.       } ;
  320.    } ;
  321. }
  322.  
  323. ExpandTemplate ( template, fulltemplate, pathname  ) 
  324.  
  325.    char  template     [] ;
  326.    char  fulltemplate [] ;
  327.    char  pathname     [] ;
  328.  
  329. /*
  330.          +--------------------------------------------------+
  331.          |                                                  |
  332.          |  This procedure expands the template given by    |
  333.          |  the user into a somewhat fuller template.  The  |
  334.          |  path name is also returned.                     |
  335.          |                                                  |
  336.          +--------------------------------------------------+
  337. */
  338.  
  339. {
  340.    int    i , j    ;
  341.    int    colon    ;
  342.    int    dot      ;
  343.    int    wild     ;
  344.  
  345.       /*  Get the files associated with template  */
  346.  
  347.    j = i = strlen ( template  ) ;
  348.    fulltemplate [0] = '\0' ;
  349.    getcwd ( pathname, MAXPATH ) ;
  350.    strcat ( pathname, "\\"    ) ;
  351.  
  352.    colon    = FALSE ;
  353.    wild     = FALSE ;
  354.    dot      = FALSE ;
  355.    while ( --i >= 0 ) {
  356.       if ( template [i] == '\\' || template [i] == '/' ) {
  357.          strcpy ( pathname     , template ) ;
  358.          if ( dot )
  359.             pathname [i+1] = '\0' ;
  360.          if ( pathname [strlen(pathname)-1] != '\\' )
  361.             strcat ( pathname, "\\" ) ; 
  362.          strcpy ( fulltemplate , template ) ;
  363.          if ((! wild && ! dot) ) {
  364.             if ( j > i+1 )
  365.                strcat ( fulltemplate, "\\" ) ;
  366.             strcat ( fulltemplate, "*.*" ) ;
  367.          } ;
  368.          break ;
  369.       } 
  370.       else if ( template [i] == ':' )
  371.          colon    = TRUE ;
  372.       else if ( template [i] == '*' || template [i] == '?' )
  373.          wild     = TRUE ;
  374.       else if ( template [i] == '.' )
  375.          dot      = TRUE ;
  376.    } ;
  377.    if ( i < 0 ) {
  378.       if ( ! wild && ! colon ) {
  379.          getcwd ( fulltemplate, MAXPATH   ) ;
  380.          i = strlen ( fulltemplate ) ;
  381.          if ( fulltemplate [i-1] != '\\' )
  382.             strcat ( fulltemplate, "\\" ) ;
  383.          strcpy ( pathname, fulltemplate ) ;
  384.          strcat ( fulltemplate, template ) ;
  385.          if ( ! dot )
  386.             strcat ( fulltemplate, ".*"  ) ;
  387.       }
  388.       else {
  389.          strcpy ( fulltemplate, template ) ;
  390.          if ( colon )
  391.             pathname [2] = '\0' ;
  392.          if ( ! wild && ! dot )
  393.             strcat ( fulltemplate, "*.*" ) ;
  394.       } ;
  395.    } ;
  396.    strupr ( pathname     ) ;
  397.    strupr ( fulltemplate ) ;
  398. }
  399.  
  400. GetTraceFile ()
  401.  
  402. /*
  403.          +--------------------------------------------------+
  404.          |                                                  |
  405.          |  This procedure asks the user for the file name  |
  406.          |  on which the trace file is to be written.  It   |
  407.          |  then opens it.                                  |
  408.          |                                                  |
  409.          +--------------------------------------------------+
  410. */
  411.  
  412. {
  413.    int   FileName   ;
  414.    int   ReTry      ;
  415.    int   length     ;
  416.  
  417.    FileName = FALSE ;
  418.    while ( ! FileName  ) {              
  419.       printf ( "Enter file on which trace output is be written.\n" ) ;
  420.       printf ( ">>> " ) ;
  421.       length = FGetLine ( stdin, InputLine, 40 ) ;
  422.       if ( length > 0 )
  423.          strcpy ( OutputFileName, InputLine ) ;
  424.       else
  425.          continue ;
  426.  
  427.       ReTry    = FALSE ;
  428.       if ( ( OutputFile = fopen ( OutputFileName, "r" ) ) != NULL ) {
  429.          fclose ( OutputFile ) ;
  430.          printf ( "The file '%s' currently exists.  ", OutputFileName ) ;
  431.          length = 0 ;
  432.          while ( length == 0 ) {
  433.             printf ( "Do you want to overwrite it? \n"   ) ;
  434.             printf ( ">>> " ) ;
  435.             length = FGetLine ( stdin, InputLine, 20 ) ;
  436.             if ( toupper ( InputLine[0] ) != 'Y' ) 
  437.                ReTry = TRUE ;
  438.          } ;
  439.       } ;
  440.       if ( ReTry )
  441.          continue ;
  442.             
  443.       if ( ( OutputFile = fopen ( OutputFileName, "w" ) ) == NULL )
  444.          printf ( "Unable to open '%s'.\n", OutputFileName ) ;
  445.       else 
  446.          FileName = TRUE ;
  447.    } ;
  448. }
  449.  
  450. OpenNextFile ()
  451.  
  452. /*
  453.          +--------------------------------------------------+
  454.          |                                                  |
  455.          |  This procedure is called to open the next file  |
  456.          |  based on the current file template.  A return   |
  457.          |  value of FALSE indicates no more files for this |
  458.          |  template.                                       |
  459.          |                                                  |
  460.          +--------------------------------------------------+
  461. */
  462.  
  463. {
  464.    int     i, max    ;
  465.  
  466.    InputLineNumber = 0 ;
  467.    fclose ( InputFile ) ;
  468.    if ( nestlevel > 0 )
  469.       printf ("Warning:  Unbalanced brackets in %s\n",InputFileName) ;
  470.    nestlevel = 0 ;
  471.  
  472.    while ( _dos_findnext ( &filespec ) == 0 ) {
  473.       filenames [++nrfiles] = malloc ( strlen ( filespec.name ) + 1 ) ;
  474.       if ( filenames [nrfiles] == NULL ) {
  475.          printf ( "Out of memory.\n" ) ;
  476.          exit ( 1 ) ;
  477.       } ;
  478.       if ( nrfiles >= MAXFILES ) {
  479.          printf ( "Too many files.\n" ) ;
  480.          exit ( 1 ) ;
  481.       } ;
  482.  
  483.       strcpy ( filenames [nrfiles] , filespec.name ) ;
  484.       strcpy ( InputFileName, pathname ) ;
  485.       strcat ( InputFileName, filespec.name ) ;
  486.       if ( ( InputFile = fopen ( InputFileName, "r" ) ) != NULL ) {
  487.          i = FGetLine ( InputFile, InputLine, 2*MAX_INPUT ) ;
  488.          if ( i == EOF ) {
  489.             fclose ( InputFile ) ;
  490.             printf ( "Empty input file -> %s\n", InputFileName ) ;
  491.             continue ;
  492.          }
  493.          else {
  494.             SetSegmentNumber ( filenames [nrfiles] ) ;
  495.             printf ( "Cross-referencing file %s", InputFileName ) ;
  496.             max = 32 - strlen ( InputFileName ) ;
  497.             for ( i = 0 ; i < max ; i++ )
  498.                putchar ( ' ' ) ;
  499.             putchar ( '\r' ) ;
  500.          } ;
  501.       }
  502.       else {
  503.          printf ( "Unable to open file -> %s\n", InputFileName ) ;
  504.          continue ;
  505.       } ;
  506.       eofflag = FALSE ;
  507.       return ( TRUE ) ;
  508.    } ;
  509.    return ( FALSE ) ;
  510. }
  511.  
  512. FGetLine ( FilePtr, Text, MaxText )
  513.                    
  514.    FILE *FilePtr ;                   /* Pointer to file    */
  515.    char  Text [] ;                   /* Read text from TTY */        
  516.    int   MaxText ;                   /* Max. text to read  */
  517.  
  518. /*
  519.          +--------------------------------------------------+
  520.          !                                                  !
  521.          !         Read a line of text from file/user       !
  522.          !                                                  !
  523.          +--------------------------------------------------+
  524. */
  525.  
  526. {
  527.    int   i,  c, toolong ;
  528.  
  529.    i = 0 ;
  530.    toolong = FALSE ;
  531.    while ( (c=getc(FilePtr)) != EOF && c != '\n'  )
  532.       if ( i < MaxText-1 )
  533.          Text [i++] = c ;
  534.       else
  535.          toolong = TRUE ;
  536.    Text [i] = '\0' ;
  537.    if ( c != EOF  )
  538.       InputLineNumber++ ;
  539.    else 
  540.       i = EOF ;
  541.    if ( toolong )
  542.       printf ( "Error: Input record exceeds maximum - %d\n",
  543.                          MaxText-1 ) ;
  544.    if ( Text [0] == '#' )
  545.       poundsign = TRUE ;
  546.    else
  547.       poundsign = FALSE ;
  548.    return ( i )    ;
  549. }
  550.  
  551. GetNextProc ( symbol ) 
  552.  
  553.    char   symbol[] ;      /* Text of Procedure name          */
  554.  
  555. /*
  556.          +--------------------------------------------------+
  557.          |                                                  |
  558.          |  This procedure will get the next procedure name |
  559.          |  in the input stream (returned in 'symbol').     |
  560.          |                                                  |
  561.          |  The calling format is as follows:               |
  562.          |                                                  |
  563.          |     if (   GetNextProc ( symbol ) ) ... ;        |
  564.          |                                                  |
  565.          |  A return value of TRUE indicates a proc. was    |
  566.          |  found (which is returned in 'symbol').          |
  567.          |                                                  |
  568.          +--------------------------------------------------+
  569. */
  570.                     
  571. {
  572.    int    SymbolLength         ;
  573.    int    table                ;
  574.    int    parens               ;
  575.    char   scratch [MAX_SYMBOL] ;
  576.  
  577.  
  578. Retry:
  579.    SymbolLength = GetSymbol ( &nscb, InputLine, symbol, MAX_SYMBOL ) ; 
  580.  
  581. Retry1:
  582.    if ( nscb.nextt == IDENTIFIER ) {
  583.  
  584.       if ( IsKeyword ( symbol ) )
  585.           goto Retry  ;
  586.       if ( ! librarycalls && IsLibraryCall ( symbol ) )
  587.           goto Retry  ;
  588.       SymbolLength = GetSymbol ( &nscb, InputLine, scratch, MAX_SYMBOL ) ; 
  589.       if ( nscb.nextt == SPECIAL && scratch [0] == '(' ) {
  590.          if ( nestlevel == 0 ) {
  591.             parens = 1 ;
  592.             while ( nscb.nextt != EOS && parens > 0 ) {
  593.                SymbolLength = GetSymbol ( &nscb, InputLine, scratch,
  594.                                           MAX_SYMBOL ) ; 
  595.                if ( nscb.nextt == SPECIAL ) {
  596.                   if ( scratch [0] == '(' )
  597.                      parens++ ;
  598.                   else if ( scratch [0] == ')' )
  599.                      parens-- ;
  600.                } ;
  601.             } ;
  602.             if ( parens == 0 && ! poundsign ) {
  603.                SymbolLength = GetSymbol ( &nscb, InputLine, scratch, 
  604.                                           MAX_SYMBOL ) ; 
  605.                if ( nscb.nextt == SPECIAL && ( scratch [0] == ';' ||
  606.                                                scratch [0] == ','   )  ) {
  607.                   strcpy ( symbol, scratch ) ;
  608.                   goto Retry1 ;
  609.                } ;
  610.             } ;
  611.          } ;
  612.          return ( TRUE ) ;
  613.       } ;
  614.       strcpy ( symbol, scratch ) ;
  615.       goto Retry1 ;
  616.    } ;
  617.  
  618.    if ( nscb.nextt == SPECIAL ) {
  619.       if ( symbol [0] == '/' && InputLine [nscb.nextp] == '*' ) {
  620. Con:
  621.          while ( InputLine [++nscb.nextp] != '*'  ) 
  622.             if ( InputLine [nscb.nextp] == '\0' ) {
  623.                table = FGetLine ( InputFile, InputLine, 2*MAX_INPUT ) ;
  624.                if ( table == EOF )
  625.                   return ( FALSE ) ;
  626.                nscb.nextp = -1 ;
  627.             } ;
  628.          nscb.nextp++ ;
  629.          if ( InputLine [nscb.nextp] != '/' ) {
  630.             nscb.nextp-- ;
  631.             goto Con ;
  632.          } ;
  633.          nscb.nextp++ ;
  634.       } 
  635.       else if ( symbol [0] == '{' ) 
  636.          nestlevel++ ;
  637.       else if ( symbol [0] == '}' ) 
  638.          nestlevel-- ;
  639.       else if ( symbol [0] == '\"' ) {
  640.          table = strlen ( InputLine ) ;
  641. Quoted:
  642.          if ( InputLine [table-1] == '\\' ) {
  643.             table = FGetLine ( InputFile, InputLine, 2*MAX_INPUT ) ;
  644.             if ( table == EOF )
  645.                return ( FALSE ) ;
  646.             nscb.nextp = -1 ;
  647.             while ( InputLine [++nscb.nextp] != '\"' &&
  648.                     InputLine [  nscb.nextp] != '\0'    ) 
  649.                ;
  650.             if ( InputLine [nscb.nextp] == '\0' )
  651.                goto Quoted ;
  652.          } ;
  653.          goto Retry  ;
  654.       } ;
  655.    } ;
  656.  
  657.    if ( nscb.nextt == EOS ) {
  658.       table  = FGetLine (InputFile, InputLine, 2*MAX_INPUT) ;
  659.       if ( table == EOF ) 
  660.          return ( FALSE ) ;
  661.       else {
  662.          nscb.nextp = 0 ;
  663.          goto Retry ;
  664.       } ;
  665.    } ;
  666.    goto Retry ;
  667. }
  668.  
  669. IsKeyword ( Symbol )
  670.  
  671.    char  Symbol []   ;         /* Symbol which is to be classified */
  672.  
  673. /*
  674.          +--------------------------------------------------+
  675.          |                                                  |
  676.          |   This procedure will classify the Symbol as     |
  677.          |   to whether it is a 'C' keyword or not.         |
  678.          |                                                  |
  679.          +--------------------------------------------------+
  680. */
  681.  
  682. {
  683.    static KEYWORD Keywords [] = {
  684.       4, "auto"            ,         
  685.       5, "break"           ,  
  686.       4, "case"            ,  
  687.       5, "cdecl"           ,  
  688.       4, "char"            ,    
  689.       8, "continue"        ,  
  690.       7, "default"         ,  
  691.       6, "define"          ,  
  692.       7, "defined"         ,
  693.       2, "do"              ,        
  694.       6, "double"          ,         
  695.       4, "else"            ,  
  696.       5, "endif"           ,
  697.       6, "extern"          ,  
  698.       3, "far"             ,
  699.       5, "float"           ,  
  700.       3, "for"             ,         
  701.       7, "fortran"         ,  
  702.       4, "goto"            ,  
  703.       4, "huge"            ,
  704.       2, "if"              ,         
  705.       5, "ifdef"           ,  
  706.       6, "ifndef"          ,  
  707.       7, "include"         ,
  708.       3, "int"             ,     
  709.       4, "line"            ,
  710.       4, "long"            ,     
  711.       4, "near"            ,
  712.       6, "pascal"          ,  
  713.       8, "register"        ,  
  714.       6, "return"          ,  
  715.       5, "short"           ,     
  716.       6, "static"          ,         
  717.       6, "struct"          ,        
  718.       6, "switch"          ,         
  719.       7, "typedef"         ,         
  720.       5, "undef"           ,  
  721.       5, "union"           ,         
  722.       8, "unsigned"        ,     
  723.       4, "void"            ,
  724.       5, "while"
  725.    } ;
  726. #define KeywordsLength   ( sizeof (Keywords ) / sizeof (struct key_entry) )
  727.  
  728.    int   SymbolLength ;
  729.    int   i            ;
  730.  
  731.    SymbolLength = strlen ( Symbol ) ;
  732.    for ( i = 0 ; i < KeywordsLength ; i++ )
  733.       if ( SymbolLength == Keywords [i].length &&
  734.            strcmp ( Symbol, Keywords [i].key ) == 0 )
  735.          return ( TRUE ) ;
  736.    return ( FALSE ) ;
  737. }
  738.  
  739. IsLibraryCall ( Symbol )
  740.  
  741.    char  Symbol []   ;         /* Symbol which is to be classified */
  742.  
  743. /*
  744.          +--------------------------------------------------+
  745.          |                                                  |
  746.          |   This procedure will classify the Symbol as     |
  747.          |   to whether it is a 'C' libary routine or not.  |
  748.          |                                                  |
  749.          +--------------------------------------------------+
  750. */
  751.  
  752. {
  753.    static KEYWORD Procwords [] = {
  754.        3, "abs"             ,
  755.        5, "abort"           ,
  756.        6, "access"          ,
  757.        4, "acos"            ,
  758.        7, "asctime"         ,
  759.        4, "asin"            ,
  760.        4, "atan"            ,
  761.        5, "atan2"           ,
  762.        4, "atof"            ,    
  763.        4, "atoi"            ,    
  764.        4, "atol"            ,    
  765.        4, "bdos"            ,
  766.        6, "calloc"          ,
  767.        5, "cgets"           ,
  768.        5, "chdir"           ,
  769.        5, "chmod"           ,
  770.        6, "chsize"          ,
  771.        8, "clearerr"        ,
  772.        5, "close"           ,
  773.        3, "cos"             ,
  774.        4, "cosh"            ,
  775.        7, "cprintf"         ,
  776.        5, "cputs"           ,
  777.        5, "creat"           ,
  778.        6, "cscanf"          ,    
  779.        5, "ctime"           ,
  780.        3, "eof"             ,    
  781.        4, "exit"            ,     
  782.        6, "fclose"          ,
  783.        4, "feof"            ,
  784.        5, "fgetc"           ,
  785.        5, "fgets"           ,     
  786.        5, "fopen"           ,     
  787.        7, "fprintf"         ,
  788.        5, "fputc"           ,
  789.        5, "fputs"           ,     
  790.        6, "FP_OFF"          ,    
  791.        6, "FP_SEG"          ,    
  792.        5, "fread"           ,  
  793.        4, "free"            ,
  794.        7, "freopen"         ,
  795.        6, "fscanf"          ,         
  796.        5, "fseek"           ,        
  797.        5, "ftell"           ,
  798.        5, "fwrite"          ,
  799.        4, "gcvt"            ,
  800.        7, "gdosint"         ,         
  801.        4, "getc"            ,
  802.        4, "gets"            ,         
  803.        7, "isalpha"         ,  
  804.        7, "iscntrl"         ,  
  805.        7, "isdigit"         ,         
  806.        7, "isprint"         ,         
  807.        4, "itoa"            ,    
  808.        4, "ltoa"            ,    
  809.        6, "malloc"          ,        
  810.        3, "min"             ,        
  811.        6, "printf"          ,         
  812.        4, "putc"            ,    
  813.        5, "qsort"           ,    
  814.        6, "sizeof"          ,         
  815.        7, "sprintf"         ,  
  816.        6, "strcat"          ,  
  817.        6, "strcmp"          ,  
  818.        7, "strcmpi"         ,  
  819.        6, "strcpy"          ,  
  820.        6, "strlen"          ,  
  821.        7, "strncpy"         ,  
  822.        6, "strupr"          ,  
  823.        4, "time"            ,    
  824.        7, "toupper"         ,
  825.        5, "write"
  826.    } ;
  827. #define ProcwordsLength   ( sizeof (Procwords) / sizeof (struct key_entry) )
  828.  
  829.    int   SymbolLength ;
  830.    int   i            ;
  831.  
  832.    SymbolLength = strlen ( Symbol ) ;
  833.    for ( i = 0 ; i < ProcwordsLength ; i++ )
  834.       if ( SymbolLength == Procwords [i].length &&
  835.            strcmp ( Symbol, Procwords [i].key ) == 0 )
  836.          return ( TRUE ) ;
  837.    return ( FALSE ) ;
  838. }
  839.  
  840. WORDNODEPTR  AddToTree ( subtree, word, linenumber )
  841.  
  842.    WORDNODEPTR  subtree    ;
  843.    char         word  []   ;
  844.    int          linenumber ;
  845.  
  846.  
  847. /*
  848.          +--------------------------------------------------+
  849.          |                                                  |
  850.          |   This procedure will attempt to place the word  |
  851.          |   'word' in the binary tree pointed to by        |
  852.          |   'subtree'.                                     |
  853.          |                                                  |
  854.          +--------------------------------------------------+
  855. */
  856.  
  857. {
  858.    char    *strsave ()     ;
  859.    int      cond           ;
  860.    LINENODEPTR   ptr       ;
  861.  
  862.  
  863.    if ( subtree == NULL )  {
  864.       if ( linenumber >= 0 )
  865.          totalsymbols++ ;
  866.       subtree = (WORDNODEPTR) malloc ( sizeof ( WORDNODE ) ) ;
  867.       if ( subtree == NULL ) {
  868.          printf ( "Out of memory." ) ;
  869.          exit ( 1 ) ;
  870.       } ;
  871.       subtree->left  = NULL ;
  872.       subtree->right = NULL ;
  873.       subtree->word   = strsave ( word ) ;
  874.       subtree->printpage = -1 ;
  875.       calledprocedure = subtree->word ;
  876.       if ( linenumber >= 0 ) {
  877.          subtree->filename   = filenames [nrfiles] ;
  878.          entersegment ( CurrentSegment, subtree->word ) ;
  879.       } 
  880.       else
  881.          subtree->filename   = NULL ;
  882.       subtree->linenumber = linenumber ;
  883.       subtree->firstlinenode = NULL ;
  884.       subtree->lastlinenode  = NULL ;
  885.    }
  886.    else if ( ( cond = strcmpi ( word, subtree->word ) ) == 0 &&
  887.              ( cond = strcmp  ( word, subtree->word ) ) == 0   ) {
  888.       if ( subtree->filename != NULL && linenumber >= 0 ) {
  889.          if ( ! poundsign ) {
  890.             printf ( "Duplicate procedure definition --> %s\n", word ) ;
  891.             printf ( 
  892.              "  Defined in %s on line %d and in %s on line %d\n" ,
  893.                 subtree->filename, subtree->linenumber, filenames [nrfiles],
  894.                 linenumber  ) ;
  895.          } ;
  896.       } ;
  897.       
  898.       if ( linenumber >= 0 ) {
  899.          totalsymbols++ ;
  900.          subtree->filename   = filenames [nrfiles] ;
  901.          subtree->linenumber = linenumber ;
  902.          entersegment ( CurrentSegment, subtree->word ) ;
  903.       } ;
  904.       calledprocedure = subtree->word ;
  905.    }
  906.    else if ( cond < 0 )
  907.       subtree->left  = AddToTree ( subtree->left , word, linenumber ) ;
  908.    else
  909.       subtree->right = AddToTree ( subtree->right, word, linenumber ) ;
  910.  
  911.    return ( subtree ) ;
  912. }
  913.  
  914. addtree ( subtree, procedure, word )
  915.  
  916.    WORDNODEPTR  subtree      ;
  917.    char         procedure [] ;
  918.    char         word  []     ;
  919.  
  920. /*
  921.          +--------------------------------------------------+
  922.          |                                                  |
  923.          |   This procedure will attempt to place the word  |
  924.          |   'word' in the binary tree pointed to by        |
  925.          |   'subtree'.  This is an inverted list from      |
  926.          |   the tree maintained by AddToTree.              |
  927.          |                                                  |
  928.          +--------------------------------------------------+
  929. */
  930.  
  931. {
  932.    char    *strsave ()     ;
  933.    int      cond           ;
  934.    LINENODEPTR   ptr       ;
  935.  
  936.  
  937.    if ( subtree != NULL )  {
  938.       if ( ( cond = strcmpi ( procedure, subtree->word ) ) == 0 &&
  939.            ( cond = strcmp  ( procedure, subtree->word ) ) == 0   ) {
  940.          ptr = (LINENODEPTR) malloc ( sizeof (LINENODE) ) ;
  941.          if ( ptr == NULL ) {
  942.             printf ( "Out of memory" ) ;
  943.             exit ( 1 ) ;
  944.          } ;
  945.          ptr->procedure    = calledprocedure  ;
  946.          ptr->nextlinenode = NULL             ; 
  947.          if ( subtree->lastlinenode == NULL ) {
  948.             subtree->firstlinenode =  ptr ;
  949.             subtree->lastlinenode  =  ptr ;
  950.          }
  951.          else {
  952.             subtree->lastlinenode->nextlinenode = ptr ;
  953.             subtree->lastlinenode = ptr ;
  954.          } ;
  955.       }
  956.       else if ( cond < 0 )
  957.          addtree ( subtree->left , procedure, word ) ;
  958.       else
  959.          addtree ( subtree->right, procedure, word ) ;
  960.    } ;
  961.  
  962.    return ;
  963. }
  964.  
  965. char *strsave ( word ) 
  966.  
  967.    char  word  []  ;
  968.  
  969. /*
  970.          +--------------------------------------------------+
  971.          |                                                  |
  972.          |   This procedure allocates memory and saves      |
  973.          |   'word' in memory and returns a pointer to it.  |
  974.          |                                                  |
  975.          +--------------------------------------------------+
  976. */
  977.  
  978. {
  979.    char  *strloc    ;
  980.    
  981.    if ( ( strloc = malloc ( strlen ( word ) + 1 ) ) == NULL ) {
  982.       printf ( "Out of memory." ) ;
  983.       exit ( 1 ) ;
  984.    } ;
  985.    strcpy ( strloc, word ) ;
  986.    return ( strloc ) ;
  987. }
  988.  
  989. checktree ( root, subtree, procedure )
  990.  
  991.    WORDNODEPTR  root         ;
  992.    WORDNODEPTR  subtree      ;
  993.    char         procedure [] ;
  994.  
  995. /*
  996.          +--------------------------------------------------+
  997.          |                                                  |
  998.          |   This procedure calls itself recursively to     |
  999.          |   trace down all the procedures called by a      |
  1000.          |   given procedure to ensure that they are in the |
  1001.          |   proper calling heirarchy.  If they arn't,      |
  1002.          |   a trace back is performed indicating the       |
  1003.          |   errant calling heirarchy.                      |
  1004.          |                                                  |
  1005.          +--------------------------------------------------+
  1006. */
  1007.  
  1008. {
  1009.    int      cond           ;
  1010.  
  1011.    if ( subtree != NULL )  {
  1012.       if ( ( cond = strcmpi ( procedure, subtree->word ) ) == 0  &&
  1013.            ( cond = strcmp  ( procedure, subtree->word ) ) == 0   ) {
  1014.          if ( ! checkentry ( root, subtree ) ) {
  1015.             strcpy ( InputLine, margin ) ;
  1016.             strcat ( InputLine, margin ) ;
  1017.             strcat ( InputLine, "--> "    ) ;
  1018.             strcat ( InputLine, procedure ) ;
  1019.             if ( subtree->filename != NULL ) {
  1020.                strcat ( InputLine, " (" ) ;
  1021.                strcat ( InputLine, subtree->filename ) ;
  1022.                strcat ( InputLine, ")" ) ;
  1023.             } 
  1024.             else 
  1025.                strcat ( InputLine, " (????)" ) ;
  1026.             printline ( InputLine ) ;
  1027.             return ( FALSE ) ;
  1028.          } ;
  1029.       }
  1030.       else if ( cond < 0 )
  1031.          return ( checktree ( root, subtree->left , procedure ) ) ;
  1032.       else
  1033.          return ( checktree ( root, subtree->right, procedure ) ) ;
  1034.    } ;
  1035.  
  1036.    return ( TRUE ) ;
  1037. }
  1038.  
  1039. checkentry ( root, tree )
  1040.  
  1041.    WORDNODEPTR  root ;
  1042.    WORDNODEPTR  tree ;
  1043.  
  1044. /*
  1045.          +--------------------------------------------------+
  1046.          |                                                  |
  1047.          |   This procedure checks the current procedure    |
  1048.          |   to see if it is in the proper calling          |
  1049.          |   heirarchy.  If it isn't, a trace back is       |
  1050.          |   performed indicating the errant calling        |
  1051.          |   sequence.  If it is, a trace is performed      |
  1052.          |   on all procedures called by this procedure.    |
  1053.          |                                                  |
  1054.          +--------------------------------------------------+
  1055. */
  1056.  
  1057. {
  1058.    LINENODEPTR  lptr        ;
  1059.    LINENODEPTR  sort [150 ] ;
  1060.    int          nrrefs      ;
  1061.    int          pos         ;
  1062.    int          i           ;
  1063.    char  *itoa ()           ;
  1064.    char  *last              ;
  1065.    int         currentlevel ;
  1066.    static char nullstring [1] = { "" } ;
  1067.  
  1068.    if ( nestlevel > maxlevel )     /*  If at max. nesting level, return  */
  1069.       return ;
  1070.  
  1071.       /*  Check if procedure is in current segment or root  */
  1072.  
  1073.    currentlevel = nestlevel ;
  1074.    if ( tree->filename != NULL                     &&
  1075.         ! insegment ( CurrentSegment, tree->word ) &&
  1076.         ! insegment ( 0             , tree->word )    ) {
  1077.       strcpy  ( InputLine, margin ) ;
  1078.       strcat  ( InputLine, tree->word ) ;
  1079.       if ( tree->filename != NULL ) {
  1080.          strcat ( InputLine, " (" ) ;
  1081.          strcat ( InputLine, tree->filename ) ;
  1082.          strcat ( InputLine, ")" ) ;
  1083.       } 
  1084.       else 
  1085.          strcat ( InputLine, " (????)" ) ;
  1086.       strcat ( InputLine, " not in calling heirarchy." ) ;
  1087.       printline ( ""        ) ;
  1088.       printline ( InputLine ) ;
  1089.       
  1090.       return ( FALSE ) ;
  1091.    } ;
  1092.  
  1093.       /*  Perform check on all called procedures.           */
  1094.       /*  First gather up procedures called and sort them.  */
  1095.  
  1096.    lptr   = tree->firstlinenode ;
  1097.    nrrefs = 0 ;
  1098.    while ( lptr != NULL ) {
  1099.       pos = FALSE ;
  1100.       for ( i = 0 ; i < nrrefs ; i++ )
  1101.          if ( strcmpi ( lptr->procedure, sort [i]->procedure ) == 0 ) {
  1102.             pos = TRUE ;
  1103.             break ;
  1104.          } ;
  1105.       if ( ! pos ) {
  1106.          sort [nrrefs++] = lptr ;
  1107.          if ( nrrefs >= 150  ) {
  1108.             printf ("Too many procedure calls in %s.  List truncated to 150.\n",
  1109.                      tree->word ) ;
  1110.             break ;
  1111.          } ;
  1112.       } ;
  1113.       lptr = lptr->nextlinenode ;
  1114.    } ;
  1115.  
  1116.       /*  Sort the CALLS to avoid duplicate processing */
  1117.  
  1118.    qsort ( sort, nrrefs, sizeof (LINENODEPTR), Compare ) ;
  1119.  
  1120.        /*  Invoke checktree recursively  */
  1121.  
  1122.    lptr = sort [0]   ;
  1123.    last = nullstring ;
  1124.    pos  = 0          ;
  1125.    nestlevel++       ;
  1126.    while ( pos < nrrefs ) {
  1127.       if ( strcmpi ( last, lptr->procedure ) != 0 ) {
  1128.          if ( ! checktree ( root, root, lptr->procedure ) ) 
  1129.             return ( FALSE ) ;
  1130.       } ;
  1131.       last = lptr->procedure ;
  1132.       lptr = sort [++pos] ;
  1133.    } ;
  1134.    nestlevel-- ;
  1135.    return ( TRUE ) ;
  1136. }
  1137.  
  1138. Compare ( key1, key2 )
  1139.  
  1140.    LINENODEPTR  key1 []    ;
  1141.    LINENODEPTR  key2 []    ;
  1142.  
  1143. /*
  1144.          +--------------------------------------------------+
  1145.          |                                                  |
  1146.          |   This procedure is the compare procedure used   |
  1147.          |   to sort procedure names.                       |
  1148.          |                                                  |
  1149.          +--------------------------------------------------+
  1150. */
  1151.  
  1152. {
  1153.    return ( strcmpi ( key1[0]->procedure, key2[0]->procedure ) ) ;
  1154. }
  1155.  
  1156. printline ( line )
  1157.  
  1158.    char   line  []  ;
  1159.  
  1160. /*
  1161.          +--------------------------------------------------+
  1162.          |                                                  |
  1163.          |   This procedure will print a line to the output |
  1164.          |   file.  If the number of lines printed exceeds  |
  1165.          |   the page length, a page eject with header info |
  1166.          |   is printed.                                    |
  1167.          |                                                  |
  1168.          +--------------------------------------------------+
  1169. */
  1170.  
  1171. {
  1172.    int   i ;
  1173.  
  1174.    if ( ++OutputLineNumber > 60 ) {
  1175.       OutputPage++ ;
  1176.       fprintf ( OutputFile, "\f\n\n\n  CHKSEG for %s    %s",
  1177.                                                 fulltemplate,  datetime ) ;
  1178.       for ( i = strlen ( fulltemplate )  + 41  ;
  1179.             i < 70 ; i++ )
  1180.          fprintf ( OutputFile, " " ) ;
  1181.       fprintf ( OutputFile, "Page %d\n\n", OutputPage ) ;
  1182.       OutputLineNumber = 6 ;
  1183.    } ;
  1184.  
  1185.    fprintf ( OutputFile, "%s\n", line ) ;
  1186. }
  1187.   
  1188. GetSymbol ( nptr, string, symbol, maxsym )           
  1189.  
  1190.    NSCBPTR nptr      ;           /* GetSymbol control block pointer    */
  1191.    char    string[ ] ;           /* string to scan for symbol          */
  1192.    char    symbol[ ] ;           /* symbol returned                    */
  1193.    int     maxsym    ;           /* maximum symbol length to return    */
  1194.  
  1195. /*+-------------------------------------------------------------------------+ 
  1196.   !                                                                         !
  1197.   !                                                                         !
  1198.   !  PURPOSE:                                                               !
  1199.   !                                                                         !
  1200.   !    This procedure will return the next symbol in the input              !
  1201.   !    character string 'string'.  Values of where to start scanning        !
  1202.   !    for the next symbol, etc., are contained in the NSCB                 !
  1203.   !    control block pointed to by 'nptr'.                                  !
  1204.   !                                                                         !
  1205.   !    GetSymbol is invoked as follows:                                     !
  1206.   !                                                                         !
  1207.   !         symlc   =  GetSymbol  ( &nscb, string, symbol, maxsym ) ;       !
  1208.   !                                                                         !
  1209.   !    where the value returned (symlc) is the symbol length in chars.      !
  1210.   !    The length of the symbol (symlc) does not include a zero byte        !
  1211.   !    which terminates the symbol.  This zero byte is accounted for in     !
  1212.   !    the maximum symbol length which can be returned -- consequently,     !
  1213.   !    a maximum symbol of maxsym-1 will be returned.                       !
  1214.   !                                                                         !
  1215.   !  PARAMETERS:                                                            !
  1216.   !                                                                         !
  1217.   !        &nscb      - Pointer to a NSCB control block.                    !
  1218.   !        string     - Character string which is to be scanned for         !
  1219.   !                     the next symbol.                                    !
  1220.   !        symbol     - Character variable in which the the returned        !
  1221.   !                     symbol will be placed.                              !
  1222.   !        maxsym     - Maximum number of characters to return in           !
  1223.   !                     symbol.                                             !
  1224.   !  NOTES:                                                                 !
  1225.   !                                                                         !
  1226.   !        For each call to GetSymbol, the next symbol is returned          !
  1227.   !        with a classification as to the type of symbol.  Types of        !
  1228.   !        symbols parsed by this scanner are:                              !
  1229.   !                                                                         !
  1230.   !            IDENTIFIERS     LITERALS      INTEGERS                       !
  1231.   !            FLOAT           SPECIAL       EOS                            !
  1232.   !            OTHER                                                        !
  1233.   !                                                                         !
  1234.   !        For the purposes of the above definitions, an identifier         !
  1235.   !        begins with an alphabetic character and may contain alphabetic   !
  1236.   !        or numeric characters.  Additionally, for literals, the          !
  1237.   !        characters enclosed in the quote marks (either " or ') are       !
  1238.   !        returned without the enclosing quotes.   A double quote within   !
  1239.   !        a literal will cause a single quote to be returned within the    !
  1240.   !        literal (e.g., 'Tom''s House' --> Tom's House).                  !
  1241.   !                                                                         !
  1242.   !        The value for nptr->nextp must be set to the appropriate         !
  1243.   !        starting position in 'string' before the first call to           !
  1244.   !        GetSymbol.  It must also be reset after an end of string         !
  1245.   !        has been encountered.                                            !
  1246.   !                                                                         !
  1247.   !        If 'maxsym' is less than or equal to one , no textual            !
  1248.   !        symbol will be returned.  However, if the symbol is              !
  1249.   !        an integer or a floating point number, the value will be         !
  1250.   !        decoded appropriately and the type of symbol will be set.        !
  1251.   !                                                                         !  
  1252.   !                                                                         !  
  1253.   +-------------------------------------------------------------------------+*/
  1254.  
  1255.    {       
  1256.      int    save_position, symlc , n, i ;
  1257.      char   quote  ;
  1258.                                      
  1259.    /*-------------------------------------------------------------*/
  1260.    /*                    Initialize Parameters                    */
  1261.    /*-------------------------------------------------------------*/
  1262.  
  1263.      if ( nptr->nextp < 0 ) nptr->nextp = 0 ;
  1264.      if ( --maxsym < 0 ) maxsym = 0  ;
  1265.      symlc = 0 ;     
  1266.  
  1267.    /*-------------------------------------------------------------*/
  1268.    /*                    Skip leading blanks                      */
  1269.    /*-------------------------------------------------------------*/
  1270.  
  1271.      while (  string[nptr->nextp] != '\0' && isspace (string[nptr->nextp]) )
  1272.               nptr->nextp++  ;
  1273.  
  1274.    /*-------------------------------------------------------------*/
  1275.    /*                    Set start of symbol in nptr->nextc       */
  1276.    /*-------------------------------------------------------------*/
  1277.  
  1278.      nptr->nextc = nptr->nextp ;
  1279.      if ( string[nptr->nextc] == '\0' ) {
  1280.            nptr->nextt = EOS ;                             /* EOS found      */
  1281.            if ( maxsym > 0 ) symbol[0] = '\0' ;
  1282.            return ( 0 ) ;
  1283.      } ;
  1284.  
  1285.    /*-------------------------------------------------------------*/
  1286.    /*      Build symbol based on the first character encountered  */
  1287.    /*-------------------------------------------------------------*/
  1288.  
  1289.       if ( isalpha ( string[nptr->nextp] ) ) {             /* Identifier    */
  1290.            nptr->nextt = IDENTIFIER ;
  1291.            for ( ++nptr->nextp ; string[nptr->nextp] != '\0'   &&
  1292.                          ( isalpha ( string[nptr->nextp] )     ||
  1293.                            isdigit ( string[nptr->nextp] )     ||
  1294.                            string[nptr->nextp] == '\''         ||
  1295.                            string[nptr->nextp] == '_'    ) 
  1296.                            ; nptr->nextp++ ) ;
  1297.       } 
  1298.       else if ( isdigit ( string[nptr->nextp] ) ) {        /* Integer       */
  1299.            nptr->nextt = INTEGER ;
  1300.  
  1301. StillInteger:
  1302.            for ( ++nptr->nextp ; string[nptr->nextp] != '\0'  &&
  1303.                            isdigit ( string[nptr->nextp] )   ; nptr->nextp++ ) ;
  1304.            if ( string[nptr->nextp] == ',' && isdigit ( string[nptr->nextp+1]))
  1305.               goto StillInteger ;
  1306.            if ( string[nptr->nextp] == '.' ) {
  1307.  
  1308. IsFloat:
  1309.                 nptr->nextt = FLOAT ;                      /* Floating pt.  */
  1310.                 for ( ++nptr->nextp ; string[nptr->nextp] != '\0' &&
  1311.                       isdigit ( string[nptr->nextp] ) ; nptr->nextp++ ) ;
  1312.            } ; 
  1313.            if ( isalpha (string[nptr->nextp]) || string[nptr->nextp] == '\'') {
  1314.                nptr->nextt = OTHER ;
  1315.                for ( ++nptr->nextp ; string[nptr->nextp] != '\0' &&
  1316.                      ( isdigit ( string[nptr->nextp] )           ||
  1317.                        isalpha ( string[nptr->nextp] )           ||
  1318.                        string[nptr->nextp] == '.'                ||
  1319.                        string[nptr->nextp] == '\''   ) ; nptr->nextp++ ) ;
  1320.            } ;
  1321.            if ( string[nptr->nextp-1] == '.' ) {     /*  If '.' is last,     */
  1322.               nptr->nextp-- ;                        /*  assume it is period */
  1323.               if ( nptr->nextt == FLOAT )
  1324.                  nptr->nextt = INTEGER ;
  1325.            } ;
  1326.       }
  1327.       else if (( string[nptr->nextp] == '"' ) || 
  1328.                ( string[nptr->nextp] == '\'')  ) {         /* Literal maybe */
  1329.            nptr->nextt =  SPECIAL ;
  1330.            quote = string[nptr->nextp] ;
  1331.            save_position = nptr->nextc + 1 ;
  1332.  
  1333. loop:
  1334.            for ( ++nptr->nextp ; string[nptr->nextp] != '\0'     &&
  1335.                       string[nptr->nextp] != quote  ; nptr->nextp++ ) ;
  1336.            if  ( string[nptr->nextp] == '\0' ) 
  1337.                 nptr->nextp = save_position     ;          /* Unpaired " ' */
  1338.            else {
  1339.                 nptr->nextt = LITERAL ;                    /* Literal      */
  1340.                 n     = nptr->nextp - save_position  ;
  1341.                 if ( ( symlc + n ) > maxsym ) n = maxsym - symlc ;
  1342.                 for (  ; n > 0 ; n-- )
  1343.                       symbol[symlc++] = string[save_position++] ;
  1344.                 save_position = ++nptr->nextp ;
  1345.                 if (string[nptr->nextp] == quote)
  1346.                       goto loop ;
  1347.            }
  1348.       } 
  1349.       else {                                         /* Special char.*/
  1350.            if ( string[nptr->nextp] == '.' &&
  1351.                 isdigit ( string[nptr->nextp+1] ) ) 
  1352.                   goto IsFloat ;
  1353.            else {
  1354.                 nptr->nextt = SPECIAL ;
  1355.                 nptr->nextp++   ;
  1356.            }
  1357.       }
  1358.  
  1359.    /*-------------------------------------------------------------*/
  1360.    /*              Set symbol to return if not already set        */
  1361.    /*-------------------------------------------------------------*/
  1362.  
  1363.       if ( nptr->nextt != LITERAL ) {
  1364.             symlc = nptr->nextp - nptr->nextc ;
  1365.             if ( symlc > maxsym ) symlc = maxsym ;
  1366.             i     = nptr->nextc ;
  1367.             n     = 0 ;
  1368.             while (  i < nptr->nextp  )
  1369.                   symbol[n++] = string[i++] ;
  1370.        }
  1371.  
  1372.    /*-------------------------------------------------------------*/
  1373.    /*          Terminate symbol with a 0 byte.                    */
  1374.    /*-------------------------------------------------------------*/
  1375.  
  1376.        if ( symlc > 0 ) symbol[symlc] = '\0' ;
  1377.        return ( symlc ) ;                       /* Return the symbol length */
  1378.    }
  1379.  
  1380.  
  1381. GetFileSegments ()
  1382.  
  1383. /*
  1384.          +--------------------------------------------------+
  1385.          |                                                  |
  1386.          |   This procedure prompts the user for the path   |
  1387.          |   name of the file which contains the MSC        |
  1388.          |   segment link directives.  It then load the     |
  1389.          |   information into internal arrays for later     |
  1390.          |   processing.                                    |
  1391.          |                                                  |
  1392.          +--------------------------------------------------+
  1393. */
  1394.  
  1395. {
  1396.    char  symbol     [MAX_SYMBOL+1] ;
  1397.    char  lastsymbol [MAX_SYMBOL+1] ;
  1398.    int   lasttype                  ;
  1399.    int   highsegment               ;
  1400.    int   cursegment                ;
  1401.    int   done                      ;
  1402.  
  1403.    highsegment = 0     ;
  1404.    cursegment  = 0     ;
  1405.    lasttype    = 0     ;
  1406.    done        = FALSE ;
  1407.  
  1408.    while ( ! done ) {
  1409.       printf ("Enter path name of file containing segment specification\n" ) ;
  1410.       printf ( ">>> " ) ;
  1411.       if ( FGetLine ( stdin, InputFileName, MAXPATH ) > 0 ) {
  1412.          if ((InputFile = fopen ( InputFileName, "r" )) == NULL ) {
  1413.             printf ( "Unable to open file %s\n", InputFileName ) ;
  1414.             continue ;  
  1415.          } ;
  1416.          while ( ! done ) {
  1417.             if ( FGetLine ( InputFile, InputLine, 4*MAX_INPUT ) == EOF )
  1418.                break ;
  1419.             strupr ( InputLine ) ;
  1420.             nscb.nextp = 0 ;
  1421.             nscb.nextt = 0 ;
  1422.             while ( nscb.nextt != EOS ) {
  1423.                GetSymbol ( &nscb, InputLine, symbol, MAX_SYMBOL+1 ) ;
  1424.                if ( nscb.nextt == SPECIAL ) {
  1425.                   if ( symbol [0] == '(' ) {
  1426.                      cursegment  = highsegment + 1 ;
  1427.                      highsegment = cursegment      ;
  1428.                   }
  1429.                   else if ( symbol [0] == '+' || symbol [0] == ')' ) {
  1430.                      if ( lasttype == IDENTIFIER ) {
  1431.                         FileSegs [NoOfFileSegs  ].filename = 
  1432.                                                  strsave (lastsymbol)   ;
  1433.                         FileSegs [NoOfFileSegs++].filesegno= cursegment ;
  1434.                      } ;
  1435.                      if ( symbol [0] == ')' )
  1436.                         cursegment  = 0 ;
  1437.                   } ;
  1438.                }
  1439.                else if ( nscb.nextt == EOS && lastsymbol [0] != '+' ) {
  1440.                   if ( lasttype == IDENTIFIER ) {
  1441.                      FileSegs [NoOfFileSegs  ].filename  = 
  1442.                                                  strsave ( lastsymbol ) ;
  1443.                      FileSegs [NoOfFileSegs++].filesegno = cursegment   ;
  1444.                   } ;
  1445.                   done = TRUE ;
  1446.                   break ;
  1447.                } ;
  1448.                strcpy ( lastsymbol, symbol ) ;
  1449.                lasttype = nscb.nextt ;
  1450.                if ( lasttype == IDENTIFIER )
  1451.                   strcat ( lastsymbol, ".C" ) ;
  1452.             } ;
  1453.          } ;
  1454.       }
  1455.       else
  1456.          return ( FALSE ) ;
  1457.       printf (
  1458.        "*** Loaded %d object file specifications for root and %d segments\n",
  1459.             NoOfFileSegs, highsegment ) ;
  1460.    } ;
  1461.    return ( TRUE ) ;
  1462. }
  1463.  
  1464. SetSegmentNumber ( filename )
  1465.  
  1466.    char  filename []   ;
  1467.  
  1468. /*
  1469.          +--------------------------------------------------+
  1470.          |                                                  |
  1471.          |   This procedure looks up the procedure name     |
  1472.          |   passed and sets 'CurrentSegment' to the        |
  1473.          |   segment number in which the procedure was      |
  1474.          |   found.  If the procedure was not found in      |
  1475.          |   any segment, it is assumed to be in the root.  |
  1476.          |                                                  |
  1477.          +--------------------------------------------------+
  1478. */
  1479.  
  1480. {
  1481.    int   i  ;
  1482.  
  1483.    for ( i = 0 ; i < NoOfFileSegs ; i++ )
  1484.       if ( stricmp ( FileSegs [i].filename, filename ) == 0 ) {
  1485.          CurrentSegment = FileSegs [i].filesegno ;
  1486.          return ;
  1487.       } ;
  1488.    CurrentSegment = 0 ;
  1489. }
  1490.  
  1491. entersegment ( SegmentNo, ProcStringPtr )
  1492.  
  1493.    int   SegmentNo     ;
  1494.    char *ProcStringPtr ;
  1495.  
  1496. /*
  1497.          +--------------------------------------------------+
  1498.          |                                                  |
  1499.          |   This procedure adds a given procedure name     |
  1500.          |   to the linked list maintained for each         |
  1501.          |   segment number (including the root).           |
  1502.          |                                                  |
  1503.          +--------------------------------------------------+
  1504. */
  1505.  
  1506. {
  1507.    LINENODEPTR  sptr      ;
  1508.  
  1509.    if ( Segments [SegmentNo].procedure == NULL )
  1510.       Segments [SegmentNo].procedure = ProcStringPtr ;
  1511.    else {
  1512.       sptr = &Segments [SegmentNo] ;
  1513.       while ( sptr->nextlinenode != NULL )
  1514.          if ( stricmp ( sptr->procedure, ProcStringPtr ) == 0 )
  1515.             return ;
  1516.          else
  1517.             sptr = sptr->nextlinenode ;
  1518.       if ( stricmp ( sptr->procedure, ProcStringPtr ) == 0 )
  1519.          return ;
  1520.       sptr->nextlinenode = (LINENODEPTR) malloc ( sizeof (LINENODE) ) ;
  1521.       if ( sptr->nextlinenode == (LINENODEPTR) NULL ) {
  1522.          printf ( "Out of memory" ) ;
  1523.          exit ( 1 ) ;
  1524.       } ;
  1525.       sptr = sptr->nextlinenode ;
  1526.       sptr->procedure    = ProcStringPtr ;
  1527.       sptr->nextlinenode = (LINENODEPTR) NULL ;
  1528.    } ;
  1529. }
  1530.  
  1531. insegment ( segno, procedure )
  1532.  
  1533.    int   segno        ;
  1534.    char  procedure [] ;
  1535.  
  1536. /*
  1537.          +--------------------------------------------------+
  1538.          |                                                  |
  1539.          |   This procedure looks up the procedure name     |
  1540.          |   passed to see if it is in the segment number   |
  1541.          |   passed.  If it is, a value of TRUE is returned.|
  1542.          |   Otherwise, FALSE.                              |
  1543.          |                                                  |
  1544.          +--------------------------------------------------+
  1545. */
  1546. {
  1547.    LINENODEPTR  sptr  ;
  1548.  
  1549.    sptr = (LINENODEPTR) &Segments [segno] ;
  1550.    while ( sptr != (LINENODEPTR) NULL )
  1551.       if ( stricmp (sptr->procedure, procedure ) == 0 )
  1552.          return ( TRUE ) ;
  1553.       else
  1554.          sptr = sptr->nextlinenode ;
  1555.    return ( FALSE ) ;
  1556. }
  1557.